package xyz.xtt.asset.service.impl;

import static xyz.xtt.common.asset.AssertUtils.isFalse;
import static xyz.xtt.common.asset.AssertUtils.isNull;
import static xyz.xtt.common.asset.AssertUtils.isTrue;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Sets;
import com.google.common.primitives.Longs;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.api.enums.AssetTypeEnum;
import xyz.xtt.asset.api.enums.BizTypeEnum;
import xyz.xtt.asset.api.enums.ReferProtocolEnum;
import xyz.xtt.asset.api.enums.SecondEnum;
import xyz.xtt.asset.api.enums.ShowStateEnum;
import xyz.xtt.asset.api.enums.StatusAllEnum;
import xyz.xtt.asset.client.request.MintRequest;
import xyz.xtt.asset.client.response.MintResponse;
import xyz.xtt.asset.constants.ErrorMessage;
import xyz.xtt.asset.enums.OrderTypeEnum;
import xyz.xtt.asset.enums.PayUnitEnum;
import xyz.xtt.asset.service.IInnerService;
import xyz.xtt.asset.service.INftService;
import xyz.xtt.asset.service.IPayMessageService;
import xyz.xtt.asset.service.ITblCollectionService;
import xyz.xtt.asset.service.IThirdService;
import xyz.xtt.asset.vo.CreateGorupResult;
import xyz.xtt.exchange.response.AssetAuditResponse;
import xyz.xtt.pay.client.response.BusinessOrderDto;
import xyz.xtt.pay.client.response.TblPayOrderDto;

/**
 * @author huqibo
 * @date 2025/02/12
 */
@Slf4j
@Service
public class PayMessageServiceImpl implements IPayMessageService {
	@Autowired
	private IThirdService thirdService;
	@Autowired
	private INftService nftService;
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	@Autowired
	private ITblCollectionService iTblCollectionService;
	@Autowired
	private IInnerService iInnerService;

	// 支付成功 铸造资产
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void payMint(TblPayOrderDto payOrderDto) {
		AssetAuditResponse assetAudit = iInnerService.assetAuditInfo(Longs.tryParse(payOrderDto.getBusinessRefId()));
		if (Objects.isNull(assetAudit)) {
			log.info("IPayMessageService assetAudit is null:{}", JSONUtil.toJsonStr(payOrderDto));
			return;
		}
		if (assetAudit.getFirstType().equals(AssetTypeEnum.BLIND_BOX.code())) {
			this.payMintBox(assetAudit);
		} else {
			this.payMint(assetAudit);
		}

	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void payMint(Long businessOrderId) {
		Map<Long, BusinessOrderDto> businessOrderMap = iInnerService.getBusinessListByIds(Sets.newHashSet(businessOrderId));
		if (businessOrderMap.isEmpty()) {
			return;
		}
		BusinessOrderDto businessOrder = businessOrderMap.get(businessOrderId);
		isNull(businessOrder, ErrorMessage.BUSINESS_ORDER_NOT_EXISTS);
		AssetAuditResponse assetAudit = iInnerService.assetAuditInfo(Longs.tryParse(businessOrder.getGoodsId()));
		isNull(assetAudit, ErrorMessage.ASSET_AUDIT_NOT_EXISTS);
		if (assetAudit.getFirstType().equals(AssetTypeEnum.BLIND_BOX.code())) {
			this.payMintBox(assetAudit);
		} else {
			this.payMint(assetAudit);
		}
//		this.payMint(assetAudit);
	}

	@Transactional(rollbackFor = Exception.class)
	public void payMintBox(AssetAuditResponse assetAudit) {
		log.info("start payMintBox {}", JSONUtil.toJsonStr(assetAudit));
		Long assetId = assetAudit.getAssetId();
		if (Objects.nonNull(assetId) && assetId.longValue() > 0) {
			log.info("payMint assetId is invalid assetAudit:{}", JSONUtil.toJsonStr(assetAudit));
			return;
		}
		isFalse(assetAudit.getFirstType().equals(AssetTypeEnum.BLIND_BOX.code()), ErrorMessage.ASSET_MINT_TYPE_ERR);
		// 先创建 盲盒资产
		MintRequest rquest = clearMintRequest(assetAudit);
		rquest.setGiftable(StatusAllEnum.NO.code());
		MintResponse mint = nftService.mint(rquest, OrderTypeEnum.MINT);
		isNull(mint, ErrorMessage.MINT_EX);
		Boolean updateAsset = iInnerService.assetAuditPayMint(assetAudit.getId(), mint.getAssetId());
		log.info("PayMessageService payMint:{}", updateAsset);
		isFalse(pushPackage(assetAudit.getPackageIds(), mint.getAssetId()), ErrorMessage.Asset_BOX_PUSH_PACKIGE_ERROR);
		// 创建群聊
		CreateGorupResult createGorup = thirdService
				.createGorup(mint.getAssetId(), mint.getTransactionOrderId(), assetAudit.getAppUserId(), assetAudit.getAssetName());
		log.info("IPayMessageService PayAfterConsumer {}", createGorup);

		Long collectionId = assetAudit.getCollectionId();
		if (Objects.nonNull(collectionId) && collectionId.longValue() > 0) {
			iTblCollectionService.plusVer(collectionId);
		}

		// 创建盲盒下资产 循环
		List<String> fileList = JSONUtil.parseArray(assetAudit.getFileList()).toList(String.class);
		isTrue(fileList.isEmpty(), ErrorMessage.Asset_BOX_FILE_LIST_ISNULL);
		// 盲盒下 资产生成， account 中设置不可见
		fileList.forEach(file -> {
			// 修改资产铸造信息
			assetAudit.setImgPath(file);
			assetAudit.setFirstType(AssetTypeEnum.DESIGN.code());
			MintRequest mintRequest = clearMintRequest(assetAudit);
			mintRequest.setParentId(Long.valueOf(mint.getBizId()));
			mintRequest.setVisiable(StatusAllEnum.NO.code());
			mintRequest.setSecondType(SecondEnum.BOX_SECOND.getCode());
			if (StringUtils.isNotBlank(assetAudit.getPackageIds())) {
				rquest.setGiftable(StatusAllEnum.NO.code());
			}
			// 铸造
			MintResponse mint1 = nftService.mint(mintRequest, OrderTypeEnum.MINT);
			isNull(mint1, ErrorMessage.MINT_EX);
			// 权益包生成
			isFalse(pushPackage(assetAudit.getPackageIds(), mint1.getAssetId()), ErrorMessage.Asset_BOX_PUSH_PACKIGE_ERROR);
		});
		return;
	}

	private Boolean pushPackage(String packIds, Long assetId) {
		if (StringUtils.isNotBlank(packIds)) {
			boolean installAssetPackage = iInnerService.installByPackageIds(packIds, assetId);
			log.info("iAssetBenefitPackageService install:{}, packIds:{}, assetId:{}", installAssetPackage, packIds, assetId);
			return installAssetPackage;
		}
		return true;
	}

	private MintRequest clearMintRequest(AssetAuditResponse assetAudit) {
		isNull(assetAudit, ErrorMessage.ASSET_AUDIT_NOT_EXISTS);
		AssetTypeEnum assetType = AssetTypeEnum.queryConvert(assetAudit.getFirstType());
		return MintRequest
				.builder()
				.description(assetAudit.getDescription())
				.externalUrl(assetAudit.getVideoPath())
				.image(assetAudit.getImgPath())
				.name(assetAudit.getAssetName())
				.authorId(String.valueOf(assetAudit.getAppUserId()))
				.referProtocol(ReferProtocolEnum.ERC_1155.getDescription())
				.assetType(assetType.name())
				.bizId(String.valueOf(assetAudit.getId()))
				.chainId(4)
				.amount(assetAudit.getAmount())
				.price(BigDecimal.ZERO)
				.unit(PayUnitEnum.CASH.code())
				.bizId(IdUtil.getSnowflakeNextIdStr())
				.sellStartDatetime(0L)
				.sellEndDatetime(0L)
				.showState(ShowStateEnum.DOWN.code())
				.ownerType(assetAudit.getOwnerType())
				.bizType(BizTypeEnum.NFT.dbType())
				.upChain(Boolean.TRUE)
				.sellable(StatusAllEnum.YES.code())
				.giftable(StatusAllEnum.YES.code())
				.rankable(StatusAllEnum.YES.code())
				.collectionId(assetAudit.getCollectionId())
				.build();
	}

	// 铸造 普通资产

	@Transactional(rollbackFor = Exception.class)
	public void payMint(AssetAuditResponse assetAudit) {
		log.info("start payMint {}", JSONUtil.toJsonStr(assetAudit));
		Long assetId = assetAudit.getAssetId();
		if (Objects.nonNull(assetId) && assetId.longValue() > 0) {
			log.info("payMint assetId is invalid assetAudit:{}", JSONUtil.toJsonStr(assetAudit));
			return;
		}
		MintRequest rquest = clearMintRequest(assetAudit);
		if (StringUtils.isNotBlank(assetAudit.getPackageIds())) {
			rquest.setGiftable(StatusAllEnum.NO.code());
		}
		MintResponse mint = nftService.mint(rquest, OrderTypeEnum.MINT);
		isNull(mint, ErrorMessage.MINT_EX);
		CreateGorupResult createGorup = thirdService
				.createGorup(mint.getAssetId(), mint.getTransactionOrderId(), assetAudit.getAppUserId(), assetAudit.getAssetName());
		log.info("IPayMessageService PayAfterConsumer {}", createGorup);
		Long collectionId = assetAudit.getCollectionId();
		if (Objects.nonNull(collectionId) && collectionId.longValue() > 0) {
			iTblCollectionService.plusVer(collectionId);
		}
		boolean updateAsset = iInnerService.mintAfterUpdateResult(assetAudit.getId(), mint.getAssetId());
		log.info("PayMessageService payMint:{}", updateAsset);
		// 处理权益关联信息
		if (Objects.nonNull(assetAudit.getPackageIds())) {
			boolean installAssetPackage = iInnerService.installByPackageIds(assetAudit.getPackageIds(), mint.getAssetId());
			log.info("iAssetBenefitPackageService install:{}", installAssetPackage);
		}
	}

}
